<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<link rel="stylesheet" href="../style/journal.css" type="text/css" />
<style type="text/css"><!--
.googleadsense {
	margin: 2px;
	padding: 0px;
//--></style><script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
</script>
<script type="text/javascript">
_uacct = "UA-65008-1";
urchinTracker();
</script><title>sub Perl6 (*@Examples[5] is copy)</title>
</head>
<body>
<a href="index.html">Journal</a>(2005) | <a href="../blog/"><b>Blog</b></a>(2006) | <a href="http://www.fayland.org/cgi-bin/random_link.pl">RandomLink</a> | <a href="AboutFayland.html">WhoAmI</a> | <a href="LiveBookmark.html">LiveBookmark</a> | <a href="http://www.fayland.org/">HomePage</a>
<p><&lt;Previous: <a href="Perl6_ES4.html">say q:2 '@*Examples.[4] &Perl6()';</a>&nbsp;&nbsp;>>Next: <a href="Perl6_ES6.html">multi sub Examples (6, Perl6) {...}</a></p>
<h1>sub Perl6 (*@Examples[5] is copy)</h1>
<div class='content'>
<p>Category: <a href='Perl6.html'>Perl6</a> &nbsp; Keywords: <b>Perl6 sub</b></p><h3>Bubble</h3>
以前在 <a href='Perl6_ES0.html'>@Examples[0] is Perl6</a> 里一开始就稍微讲了点子程序，而在 <a href='Perl6_ES0.html'>my Perl6 @Examples[3]</a> 中也讲了子程序参数和返回类型。<br />
现在接着讲 sub/子程序

<h3>Perl 5 的代码在 Perl 6 中会怎么样？</h3>
虽然说 Perl 5 这样的代码在 Perl 6 中也是可行的：
<pre>sub say { print qq{"@_"\n}; }</pre>
但要注意一点，这里的 @_ 是只读的。下面的代码会出错：
<pre>sub cap { $_ = uc $_ for @_ }   # Error: elements of @_ are constant</pre>
如果你想要更新 @_, 用 is rw 来指定。
<pre>sub swap (*@_ is rw) { @_[0,1] = @_[1,0] }</pre>
而预先声明却不定义一个子程序，Perl 5 中可以这么写：
<pre>sub foo;</pre>
这在 Perl 6 中会报错，Perl 6 必须得这么写：（那三个点是语法的一部分。）
<pre>sub foo {...}</pre>

<h3>如何定义一个全局子程序</h3>
我们在 <a href='Perl6_ES4.html'>say q:2 '@*Examples.[4] &Perl6()';</a> 中说用 * 来声明一个真正的全局变量，而子程序也一样：
<pre># from <a href='http://www.fayland.org/Perl6/Synopsis/zh_cn/S06.pod'>S06.pod</a>
    $*next_id = 0; # 全局变量
    sub *saith($text)  { print "Yea verily, $text" } # 全局子程序

    module A {
        my $next_id = 2;    # hides any global or package $next_id / 隐藏任何全局或包变量 $next_id
        saith($next_id);    # print the lexical $next_id; / 输出词汇变量 $next_id，这里为 2
        saith($*next_id);   # print the global $next_id; / 输出全局变量 $next_id, 这里为 0
    }

    module B {
        saith($next_id);    # Unambiguously the global $next_id / 显然是全局变量 $next_id，这里为 0
    }</pre>

<h3>参数分配</h3>
<ul>在 Perl 5 中因为没有名字参数，所以传递任意几个参数给子程序都是可以的。<br />
但 Perl 6 不同，如果你定义了两个命名参数却只有传递一个，编译器就会报错。如果你定义了要数组参数而传递了标量也会报错。
<li>而有时候我们不能确定某命名参数是否传递的话，需要在前面加一个 <b>?</b>. 例子：
<pre>sub func ($a, ?$b) {
    say $a, $b;
}</pre>
这样调用 &func(1) 和 &func(1, 2) 都不会报错。
<li>有时候你不想通过传递一个带顺序的参数列表给子程序，而想指定某些参数的名字用以传递，在 Perl 6 中这是可以的。我们用 <b>+</b> 来指定一个 Named Parameters/有名参数。例如：
<pre>sub func ($a, ?$b, +$c) {
    say $a, '-', $b, '-', $c;
}
&func(1,c => 2); # 输出 1--2</pre>
注意以下几点：
<ol>
<li>带名参数是可选的。所以上面用 &func(1) 不会报错，输出 1--<br />
不过按 S06 的说法，我们可以使用 is required 使之必须。
<li>带名参数必须在位置参数（顺序参数）的后面。（S06 中虽然这么写，但是我在 pugs 里运行了是不用一定在后面的）
<li>如果没有提供带名参数，那就按顺序参数来操作。如 &func(1,2,3) 输出 1-2-3。再举个稍微复杂点的例子：
<pre>sub func ($a, ?$b, +$c, ?$d) {
    say $a, '-', $b, '-', $c, '-', $d;
}
&func(1,2,3);</pre>
没有提供带名参数，按顺序来操作，结果为 1-2-3-<br />
而 &func(1,2,3,:c<4>); 的话，结果为 1-2-4-3
<li>带名参数也可以用 Pair 写法：&func(1,:c<3>); 输出 1--3
<li>+ 可以不写。（我在 pugs 里试过不写是可以的。）
</ol>
<li>对于可选和带名参数来说，可以使用 = 来提供默认值：
<pre>sub func ($a, ?$b = 2) {
    say $a, '-', $b;
}
&func(1); # 1-2</pre>
<li>还记不记得最上面的 sub swap (*@_ is rw)，* 在此的作用是接收所有未被分配的参数。例如：
<pre>sub func ($a, ?$b, *@c) {
    say $a, '-', $b, '-', @c, '-';
}

&func(1,2,3,4,5); # 1-2-345</pre>
这里的 @c 将接收 3,4,5; 如果没有 * 会报错。
</ul>

<h3>is rw/is copy</h3>
<ul>
<li>默认命名参数是原传递参数的别名，并且该命名参数是只读的。如：
<pre>sub func ($a) {
    # $a = 2 会报错，因为默认是只读的
    say $a;
}
my $o = 1;
&func($o);</pre>
这里 $a 是 $o 的别名（$a := $o;），且 $a 是只读的。
<li>如果想在子程序里改变 $a 的值并且同时改变 $o 的值。可以使用 is rw.
<pre>sub func ($a is rw) {
    say $a;
    $a = 2;
}
my $o = 1;
&func($o); # 输出 1
say $o; # $o 变为了 2</pre>
<li>如果想在子程序里改变 $a 的值但<b>不</b>对应改变 $o 的值，可以使用 is copy.
<pre>sub func ($a is copy) {
    $a = 2;
    say $a;
}
my $o = 1;
&func($o); # 输出 2
say $o; # $o 还是为 1</pre>
<li>可以说 is rw 是按址传递，而 is copy 是按值传递。
</ul>

<h3>OUTER::</h3>
如果你在子程序里定义了 $x, 又想获得子程序外面的 $x 的话，可以使用 OUTER::
<pre>{ my $a = 1; {
   my $a=2; {
      my $a=3;
      say $a; # 3
      say $OUTER::a; # 2
      say $OUTER::OUTER::a; # 1
}}}</pre>

<h3>want</h3>
在 Perl 5 中如果区别返回值是数组和标量时我们用 wantarray, 在 Perl 6 中将不再有这东西，而用更强大的 want 来代替。例子：
<pre>given want { 
   when Scalar {...} # 返回一个标量 
   when List   {...} # 要一个列表
   when 2      {...} # 要两个值
}</pre>


<h3>Correct me when I'm wrong</h3>
Exercise more.</div>
<p><&lt;Previous: <a href="Perl6_ES4.html">say q:2 '@*Examples.[4] &Perl6()';</a>&nbsp;&nbsp;>>Next: <a href="Perl6_ES6.html">multi sub Examples (6, Perl6) {...}</a></p>
<p><strong>Options:</strong> <a href='http://del.icio.us/post?title=sub%20Perl6%20(*@Examples%5B5%5D%20is%20copy)&url=http://www.fayland.org/journal/Perl6_ES5.html'>+Del.icio.us</a></p>
<strong>Related items</strong>
<ul><li><a href='Perl6_ES14.html'>has $.Examples14 handles 'Perl6';</a> < <span class='digit'>2005-06-02 01:38:59</span> ></li><li><a href='050519.html'>Synopsis localization</a> < <span class='digit'>2005-05-19 11:21:25</span> ></li><li><a href='Perl6_ES0.html'>@Examples[0] is Perl6</a> < <span class='digit'>2005-05-19 20:26:08</span> ></li><li><a href='Perl6_ES1.html'>given @Examples[1] when Perl6</a> < <span class='digit'>2005-05-19 22:05:56</span> ></li><li><a href='Perl6_ES2.html'>@Perl6 <== @Examples xx 2</a> < <span class='digit'>2005-05-20 18:53:54</span> ></li><li><a href='Perl6_ES3.html'>my Perl6 @Examples[3]</a> < <span class='digit'>2005-05-21 13:53:16</span> ></li><li><a href='Perl6_ES4.html'>say q:2 '@*Examples.[4] &Perl6()';</a> < <span class='digit'>2005-05-22 12:24:12</span> ></li><li><a href='Perl6_ES6.html'>multi sub Examples (6, Perl6) {...}</a> < <span class='digit'>2005-05-23 22:43:33</span> ></li><li><a href='Perl6_ES7.html'>sub infix:<(7)> ($Perl6, @Examples)</a> < <span class='digit'>2005-05-24 02:16:42</span> ></li><li><a href='Perl6_ES8.html'>let @Examples[8] = 'Perl6';</a> < <span class='digit'>2005-05-24 13:05:58</span> ></li><li><a href='Perl6_ES9.html'>Perl6 | Examples & 9 ^ junction</a> < <span class='digit'>2005-05-26 12:35:29</span> ></li><li><a href='Perl6_ES10.html'>%Examples{'IO'} = open('Perl6');</a> < <span class='digit'>2005-05-30 00:24:01</span> ></li><li><a href='Perl6_ES11.html'>class Examples11 is Perl6 { ... }</a> < <span class='digit'>2005-05-30 13:31:31</span> ></li><li><a href='Perl6_ES12.html'>$Perl6 = $class.bless(:Example<12>);</a> < <span class='digit'>2005-05-31 11:38:46</span> ></li><li><a href='Perl6_ES13.html'>role Example13 { # Perl6 }</a> < <span class='digit'>2005-05-31 18:22:03</span> ></li><li><a href='Perl6_ES16.html'>my subtype Examples16 of Perl6 where /^kissu$/</a> < <span class='digit'>2005-06-04 23:59:29</span> ></li><li><a href='Perl6_ES17.html'>my enum Example17 <<:Perl(6) Today>></a> < <span class='digit'>2005-06-05 12:14:08</span> ></li><li><a href='Perl6_ES18.html'>my $queen; rule me {Perl6|Examples18}</a> < <span class='digit'>2005-06-06 12:26:32</span> ></li><li><a href='Perl6_ES19.html'>m:nth(19)/Perl6Examples/</a> < <span class='digit'>2005-06-06 22:02:01</span> ></li><li><a href='Perl6_Rules.html'>用 Perl6::Rules 来写 Formatter</a> < <span class='digit'>2005-09-27 10:02:45</span> ></li></ul>
Created on <span class="digit">2005-05-22 15:37:26</span>, Last modified on <span class="digit">2005-05-24 23:45:37</span><br />
Copyright 2004-2005 All Rights Reserved. Powered by <a href="Eplanet.html">Eplanet</a> && <a href='http://catalyst.perl.org'>Catalyst</a> 5.62.
</body>
</html>